{
libxl_ctx *ctx;
struct stat stat_buf;
+ const pthread_mutex_t mutex_value = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
if (version != LIBXL_VERSION)
return ERROR_VERSION;
memset(ctx, 0, sizeof(libxl_ctx));
ctx->lg = lg;
+ /* This somewhat convoluted approach is needed because
+ * PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP is defined to be valid
+ * only as an initialiser, not as an expression. */
+ memcpy(&ctx->lock, &mutex_value, sizeof(ctx->lock));
+
if ( stat(XENSTORE_PID_FILE, &stat_buf) != 0 ) {
LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Is xenstore daemon running?\n"
"failed to stat %s", XENSTORE_PID_FILE);
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <pthread.h>
#include <xs.h>
#include <xenctrl.h>
xc_interface *xch;
struct xs_handle *xsh;
+ pthread_mutex_t lock; /* protects data structures hanging off the ctx */
+ /* Always use CTX_LOCK and CTX_UNLOCK to manipulate this.
+ *
+ * You may acquire this mutex recursively if it is convenient to
+ * do so. You may not acquire this lock at the same time as any
+ * other lock. If you need to call application code outside
+ * libxl (ie, a callback) with this lock held then it is
+ * necessaray to impose restrictions on the caller to maintain a
+ * proper lock hierarchy, and these restrictions must then be
+ * documented in the libxl public interface.
+ */
+
/* for callers who reap children willy-nilly; caller must only
* set this after libxl_init and before any other call - or
* may leave them untouched */
#define CTX libxl__gc_owner(gc)
+/* Locking functions. See comment for "lock" member of libxl__ctx. */
+
+#define CTX_LOCK do { \
+ int mutex_r = pthread_mutex_lock(&CTX->lock); \
+ assert(!mutex_r); \
+ } while(0)
+
+#define CTX_UNLOCK do { \
+ int mutex_r = pthread_mutex_unlock(&CTX->lock); \
+ assert(!mutex_r); \
+ } while(0)
+
+
+
/*
* Inserts "elm_new" into the sorted list "head".
*